package com.md.notes.model.module.socket;

import android.os.Handler;
import android.os.Looper;
import java.io.*;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class FileSender {
    private static final int PROTOCOL_VERSION = 0x01;
    private static final int BUFFER_SIZE = 8192; // 8KB
    private static final int SOCKET_TIMEOUT = 30000; // 30秒

    private final Handler mainHandler = new Handler(Looper.getMainLooper());
    private ProgressListener progressListener;

    public interface ProgressListener {
        void onTotalFiles(int total);
        void onFileProgress(String filename, long transferred, long total);
        void onComplete();
        void onError(String message);
    }

    public void setProgressListener(ProgressListener listener) {
        this.progressListener = listener;
    }

    public void sendFolder(String ip, int port, File folder) {
        new Thread(() -> {
            try {
                Socket socket = new Socket(ip, port);
                socket.setSoTimeout(SOCKET_TIMEOUT);
                DataOutputStream dos = new DataOutputStream(socket.getOutputStream());

                // 发送协议头
                sendFolderHeader(dos, folder);

                // 递归发送文件
                int[] fileCounter = {0};
                traverseFolder(dos, folder, "", fileCounter);

                // 触发完成回调
                safeCallback(() -> progressListener.onComplete());

                // 关闭资源
                dos.close();
                socket.close();
            } catch (IOException e) {
                safeCallback(() -> progressListener.onError(e.getMessage()));
            }
        }).start();
    }

    private void sendFolderHeader(DataOutputStream dos, File folder) throws IOException {
        // 协议版本 (1字节)
        dos.writeByte(PROTOCOL_VERSION);

        // 文件夹名称 (UTF8字符串)
        String folderName = folder.getName();
        dos.writeUTF(folderName);

        // 文件总数 (long型)
        int totalFiles = countFiles(folder);
        dos.writeLong(totalFiles);
        dos.flush();

        safeCallback(() -> progressListener.onTotalFiles(totalFiles));
    }

    private int countFiles(File folder) {
        int count = 0;
        File[] files = folder.listFiles();
        if (files != null) {
            for (File f : files) {
                if (f.isDirectory()) {
                    count += countFiles(f);
                } else if (f.isFile()) {
                    count++;
                }
            }
        }
        return count;
    }

    private void traverseFolder(DataOutputStream dos, File dir,
                                String basePath, int[] counter) throws IOException {
        File[] files = dir.listFiles();
        if (files == null) return;

        for (File file : files) {
            String relativePath = basePath.isEmpty() ?
                    file.getName() : basePath + "/" + file.getName();

            if (file.isDirectory()) {
                traverseFolder(dos, file, relativePath, counter);
            } else {
                sendSingleFile(dos, file, relativePath);
                counter[0]++;
                safeCallback(() -> progressListener.onFileProgress(
                        relativePath, counter[0], -1
                ));
            }
        }
    }

    private void sendSingleFile(DataOutputStream dos, File file,
                                String relativePath) throws IOException {
        // 文件标识 (1字节)
        dos.writeByte(0x02);

        // 相对路径 (UTF8字符串)
        dos.writeUTF(relativePath);

        // 文件大小 (long型)
        long fileSize = file.length();
        dos.writeLong(fileSize);
        dos.flush();

        // 使用NIO加速文件读取
        try (FileInputStream fis = new FileInputStream(file);
             FileChannel channel = fis.getChannel()) {

            ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
            long transferred = 0;

            while (channel.read(buffer) != -1) {
                buffer.flip();
                byte[] data = new byte[buffer.remaining()];
                buffer.get(data);
                dos.write(data);
                transferred += data.length;

                // 更新进度
                final long current = transferred;
                safeCallback(() -> progressListener.onFileProgress(
                        relativePath, current, fileSize
                ));

                buffer.clear();
            }
        }
        dos.flush();
    }

    private void safeCallback(Runnable action) {
        mainHandler.post(() -> {
            if (progressListener != null) {
                action.run();
            }
        });
    }
}